#include "lista.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

/* ******************************************************************
 *                        PRUEBAS UNITARIAS							*
 * *****************************************************************/
 
/* Función auxiliar para imprimir si estuvo OK o no. */
void print_test(char* name, bool result) {
    printf("%s: %s\n", name, result? "OK" : "ERROR");
}

void prueba_lista () {
	 /* Declaro las variables a utilizar */
	lista_t *l1;
	lista_iter_t *l1_iter1;
	
	int a = 20;
	int b = 35;
	int c = 12;
	void* valor1;
	void* valor2;
	void* valor3; 
	valor1 = &a;
	valor2 = &b;
	valor3 = &c;

    /* *********************
     * PRUEBAS DE LA LISTA *
     * *********************/
    printf ("\nPRUEBAS DE LA LISTA.\n\n");
    
    /* Pruebo la creación de una lista vacía */
    l1 = lista_crear();
    print_test("Prueba lista crear l1", l1 != NULL);
    print_test("Prueba lista_esta_vacia l1 es true", lista_esta_vacia(l1) == true);
    print_test("Prueba largo l1 es cero", lista_largo(l1) == 0);

    /* Pruebo ver y borrar primero de una lista vacía */
    print_test("Prueba ver primero l1 (vacia) es NULL", lista_ver_primero(l1) == NULL);
    print_test("Prueba borrar primero l1 (vacia) es NULL", lista_borrar_primero(l1) == NULL);
    
    /* Pruebo insertar un elemento a la primera posicion de una lista vacía */
    print_test("Prueba insertar primero l1 (vacía) es true", lista_insertar_primero(l1,valor1) == true);
    print_test("Prueba ver primero l1 es 20", lista_ver_primero(l1) == valor1);
    print_test("Prueba ver primero l1 es 20 (para ver si solo lo ve)", lista_ver_primero(l1) == valor1);
    print_test("Prueba lista_esta_vacia l1 es false", lista_esta_vacia(l1) == false);
    
    /* Pruebo insertar un elemento mas a la primera posicion */
	print_test("Prueba insertar primero l1 (con un elemento) es true", lista_insertar_primero(l1,valor2) == true);
	print_test("Prueba ver primero l1 es 35", lista_ver_primero(l1) == valor2);
    print_test("Prueba ver primero l1 es 35 (para ver si solo lo ve)", lista_ver_primero(l1) == valor2);
    print_test("Prueba lista_esta_vacia l1 es false", lista_esta_vacia(l1) == false);
    
    /* Pruebo borrar el primer elemento de la lista con dos elementos */
    print_test("Prueba lista borrar primero l1 (con dos elementos) es 35", lista_borrar_primero (l1) == valor2);
    print_test("Prueba ver primero l1 es 20", lista_ver_primero(l1) == valor1);
    print_test("Prueba ver primero l1 es 20 (para ver si solo lo ve)", lista_ver_primero(l1) == valor1);
    print_test("Prueba lista_esta_vacia l1 es false", lista_esta_vacia(l1) == false);
    
    /* Pruebo insertar un elemento a la ultima posicion */
    print_test("Prueba insertar ultimo l1 (con un elemento) es true", lista_insertar_ultimo(l1,valor2) == true);
    print_test("Prueba ver primero l1 es 20", lista_ver_primero(l1) == valor1);
    print_test("Prueba ver primero l1 es 20 (para ver si solo lo ve)", lista_ver_primero(l1) == valor1);
    print_test("Prueba lista_esta_vacia l1 es false", lista_esta_vacia(l1) == false);
    
    /* Pruebo borrar el primer elemento de la lista con dos elementos */
    print_test("Prueba lista borrar primero l1 (con dos elementos) es 20", lista_borrar_primero (l1) == valor1);
    print_test("Prueba ver primero l1 es 35", lista_ver_primero(l1) == valor2);
    print_test("Prueba ver primero l1 es 35 (para ver si solo lo ve)", lista_ver_primero(l1) == valor2);
    print_test("Prueba lista_esta_vacia l1 es false", lista_esta_vacia(l1) == false);
    
    /* Pruebo borrar el primer elemento de la lista con un elemento */
    print_test("Prueba lista borrar primero l1 (con un elemento) es 35", lista_borrar_primero (l1) == valor2);
    print_test("Prueba ver primero l1 (vacia) es NULL", lista_ver_primero(l1) == NULL);
    print_test("Prueba borrar primero l1 (vacia) es NULL", lista_borrar_primero(l1) == NULL);
    print_test("Prueba lista_esta_vacia l1 es true", lista_esta_vacia(l1) == true);
    print_test("Prueba largo l1 es cero", lista_largo(l1) == 0);
    
    /* Pruebo insertar ultimo en lista vacia, ver y borrar primero */
    print_test("Prueba insertar ultimo l1 (con un elemento) es true", lista_insertar_ultimo(l1,valor2) == true);
    print_test("Prueba ver primero l1 es 35", lista_ver_primero(l1) == valor2);
    print_test("Prueba lista borrar primero l1 (con un elemento) es 35", lista_borrar_primero (l1) == valor2);
    print_test("Prueba lista_esta_vacia l1 es true", lista_esta_vacia(l1) == true);
    print_test("Prueba largo l1 es cero", lista_largo(l1) == 0);
    
    /* **********************
     * PRUEBAS DEL ITERADOR *
     * **********************/
    printf ("\nPRUEBAS DEL ITERADOR.\n\n");
    
    /* Pruebo la creación de un iterador */
    l1_iter1 = lista_iter_crear (l1);
    
    /* Pruebo sus primitivas con una lista vacía */
    print_test("Prueba iterador crear l1_iter1", l1_iter1 != NULL);
    print_test("Prueba lista (vacia) iter ver actual l1_iter1 es NULL", lista_iter_ver_actual (l1_iter1) == NULL);
	print_test("Prueba lista (vacia) iter al final(?) l1_iter1 es true", lista_iter_al_final (l1_iter1) == true);
	print_test("Prueba lista (vacia) iter avanzar l1_iter1 es false", lista_iter_avanzar (l1_iter1) == false);
	
	/* Lo destruyo */
	lista_iter_destruir (l1_iter1);
	printf ("Iterador destruido.\n");
	
	/* Creo otro y pruebo sus primitivas con una lista con elementos */
	print_test("Prueba insertar primero l1 (vacía) es true", lista_insertar_primero(l1,valor1) == true);
	print_test("Prueba insertar ultimo l1 (con un elemento) es true", lista_insertar_ultimo(l1,valor2) == true);
	print_test("Prueba insertar primero l1 (con dos elementos) es true", lista_insertar_primero(l1,valor3) == true);
	l1_iter1 = lista_iter_crear (l1);
	print_test("Prueba iterador crear l1_iter1", l1_iter1 != NULL);
	
	/* Orden: al final?, veo actual, avanzo */
	/* 1 */
	print_test("Prueba lista (no vacia) iter al final(?) l1_iter1 es false", lista_iter_al_final (l1_iter1) == false);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 12", lista_iter_ver_actual (l1_iter1) == valor3);
    print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es true", lista_iter_avanzar (l1_iter1) == true);
    /* 2 */
    print_test("Prueba lista (no vacia) iter al final(?) l1_iter1 es false", lista_iter_al_final (l1_iter1) == false);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 20", lista_iter_ver_actual (l1_iter1) == valor1);
    print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es true", lista_iter_avanzar (l1_iter1) == true);
    /* 3 */
    print_test("Prueba lista (no vacia) iter al final(?) l1_iter1 es false", lista_iter_al_final (l1_iter1) == false);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 35", lista_iter_ver_actual (l1_iter1) == valor2);
    print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es true", lista_iter_avanzar (l1_iter1) == true);
    /* 4 */
    print_test("Prueba lista (no vacia) iter al final(?) l1_iter1 es true", lista_iter_al_final (l1_iter1) == true);
    print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es NULL", lista_iter_ver_actual (l1_iter1) == NULL);
    print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es false", lista_iter_avanzar (l1_iter1) == false);
    
    /* Lo destruyo */
	lista_iter_destruir (l1_iter1);
	printf ("Iterador destruido.\n");
	
	/* *****************************
	 * PRUEBAS DE LISTA E ITERADOR *
	 * *****************************/
	printf ("\nPRUEBAS DE LA LISTA Y EL ITERADOR.\n\n");
	
	/* Creo el iterador */
	l1_iter1 = lista_iter_crear (l1);
	print_test("Prueba iterador crear l1_iter1", l1_iter1 != NULL);
	
	/* Inserto estando al principio */
	print_test("Prueba lista (no vacia) iter insertar l1_iter1 es true", lista_insertar (l1,l1_iter1,valor1) == true);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 20", lista_iter_ver_actual (l1_iter1) == valor1);
	print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es true", lista_iter_avanzar (l1_iter1) == true);
	
	/* Inserto estando en 2da posicion */
	print_test("Prueba lista (no vacia) iter insertar l1_iter1 es true", lista_insertar (l1,l1_iter1,valor2) == true);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 35", lista_iter_ver_actual (l1_iter1) == valor2);
	print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es true", lista_iter_avanzar (l1_iter1) == true);

	/* Avanzo hacia el final */
	printf ("Avanzo hasta el final.\n");
	while (!lista_iter_al_final(l1_iter1)) {
		lista_iter_avanzar(l1_iter1);
	}
	printf ("Listo.\n");
	print_test("Prueba lista (no vacia) iter al final(?) l1_iter1 es true", lista_iter_al_final (l1_iter1) == true);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es NULL", lista_iter_ver_actual (l1_iter1) == NULL);
	
	/* Inserto estando al final */
	print_test("Prueba lista (no vacia) iter insertar l1_iter1 es true", lista_insertar (l1,l1_iter1,valor3) == true);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 12", lista_iter_ver_actual (l1_iter1) == valor3);
	print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es true", lista_iter_avanzar (l1_iter1) == true);
	print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es false", lista_iter_avanzar (l1_iter1) == false);
    
    /* Lo destruyo */
	lista_iter_destruir (l1_iter1);
	printf ("Iterador destruido.\n");
    
    /* Creo el iterador */
	l1_iter1 = lista_iter_crear (l1);
	print_test("Prueba iterador crear l1_iter1", l1_iter1 != NULL);
	
	/* Borro estando al principio */
	print_test("Prueba lista (no vacia) iter borrar l1_iter1 es 20", lista_borrar (l1,l1_iter1) == valor1);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 35", lista_iter_ver_actual (l1_iter1) == valor2);
	print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es true", lista_iter_avanzar (l1_iter1) == true);
	
	/* Borro estando en la 2da posicion */
	print_test("Prueba lista (no vacia) iter borrar l1_iter1 es 12", lista_borrar (l1,l1_iter1) == valor3);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 20", lista_iter_ver_actual (l1_iter1) == valor1);
	
	/* Avanzo hacia el final y pruebo primitivas */
	printf ("Avanzo hasta el final.\n");
	while (!lista_iter_al_final(l1_iter1)) {
		lista_iter_avanzar(l1_iter1);
	}
	printf ("Listo.\n");
	print_test("Prueba lista (no vacia) iter al final(?) l1_iter1 es true", lista_iter_al_final (l1_iter1) == true);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es NULL", lista_iter_ver_actual (l1_iter1) == NULL);
	print_test("Prueba lista (no vacia) iter borrar l1_iter1 es NULL", lista_borrar (l1,l1_iter1) == NULL);
	print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es false", lista_iter_avanzar (l1_iter1) == false);
	
	/* Lo destruyo */
	lista_iter_destruir (l1_iter1);
	printf ("Iterador destruido.\n");
    
    /* Creo el iterador */
	l1_iter1 = lista_iter_crear (l1);
	print_test("Prueba iterador crear l1_iter1", l1_iter1 != NULL);
	
    /* Pruebo insertar muchos elementos al principio */
    printf ("\nSe insertan 1kk de elementos al principio.\n");
    for (int i=1; i<=1000000; i++) {
		lista_insertar(l1,l1_iter1,valor3);
    }
    printf ("Listo.\n\n");
    print_test("Prueba ver primero l1 es 12", lista_ver_primero(l1) == valor3);
    print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 12", lista_iter_ver_actual (l1_iter1) == valor3);
    
    /* Avanzo e inserto mas */
    print_test("Prueba lista (no vacia) iter avanzar l1_iter1 es true", lista_iter_avanzar (l1_iter1) == true);
    printf ("\nSe insertan 1kk de elementos a partir de la 2da posicion.\n");
    for (int i=1; i<=1000000; i++) {
		lista_insertar(l1,l1_iter1,valor2);
    }
    printf ("Listo.\n\n");
    print_test("Prueba ver primero l1 es 12", lista_ver_primero(l1) == valor3);
    print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 35", lista_iter_ver_actual (l1_iter1) == valor2);
    
    /* Voy al final e inserto mas */
    printf ("Avanzo hasta el final.\n");
	while (!lista_iter_al_final(l1_iter1)) {
		lista_iter_avanzar(l1_iter1);
	}
	printf ("Listo.\n");
	print_test("Prueba lista (no vacia) iter al final(?) l1_iter1 es true", lista_iter_al_final (l1_iter1) == true);
	print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es NULL", lista_iter_ver_actual (l1_iter1) == NULL);
	printf ("\nSe insertan 1kk de elementos al final.\n");
    for (int i=1; i<=1000000; i++) {
		lista_insertar(l1,l1_iter1,valor1);
    }
    printf ("Listo.\n\n");
    print_test("Prueba ver primero l1 es 12", lista_ver_primero(l1) == valor3);
    print_test("Prueba lista (no vacia) iter ver actual l1_iter1 es 20", lista_iter_ver_actual (l1_iter1) == valor1);
    
    /* Lo destruyo */
	lista_iter_destruir (l1_iter1);
	printf ("Iterador destruido.\n");
    
    /* Creo el iterador */
	l1_iter1 = lista_iter_crear (l1);
	print_test("Prueba iterador crear l1_iter1", l1_iter1 != NULL);
	
	/* Borrado masivo */
	printf ("Borrado masivo.\n");
	while (!lista_esta_vacia(l1)) {
		lista_borrar(l1,l1_iter1);
	}
	printf ("Listo.\n");
	
    /* Destruyo la lista y el iterador para liberar la memoria pedida */
    lista_destruir (l1,NULL);
    lista_iter_destruir (l1_iter1);
    
}

/* ******************************************************************
 *                        PROGRAMA PRINCIPAL						*
 * *****************************************************************/

int main () {
	printf ("\nCOMIENZO DE PRUEBAS LISTA.\n");
	
	/* Ejecuta todas las pruebas unitarias. */
	prueba_lista ();
	
	printf ("\nFIN DE PRUEBAS LISTA.\n\n");
	return 0;
}
